use std::collections::HashMap;
use std::fmt;

#[derive(Debug, Clone)]
pub enum HttpMethod {
    GET,
    POST,
    DELETE,
    OPTIONS,
    PUT,
    HEAD,
    CONNECT,
    PATCH,
    TRACE,
    UNKNOWN,
}

#[derive(Debug)]
pub enum HttpVersion {
    HTTP11,
    UNKNOWN,
}

#[derive(Debug)]
pub struct HttpRequest {
    pub method: HttpMethod,
    pub uri: String,
    pub http_version: HttpVersion,
    pub params: HashMap<String, String>,
    pub headers: HashMap<String, String>,
    pub body: String,
}

// 为 HttpRequest 实现 Display trait
impl fmt::Display for HttpRequest {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let method_str = match self.method {
            HttpMethod::GET => "GET",
            HttpMethod::POST => "POST",
            HttpMethod::DELETE => "DELETE",
            HttpMethod::OPTIONS => "OPTIONS",
            HttpMethod::HEAD => "HEAD",
            HttpMethod::CONNECT => "CONNECT",
            HttpMethod::PUT => "PUT",
            HttpMethod::PATCH => "PATCH",
            HttpMethod::TRACE => "TRACE",
            HttpMethod::UNKNOWN => "UNKNOWN",
        };

        let version_str = match self.http_version {
            HttpVersion::HTTP11 => "HTTP/1.1",
            HttpVersion::UNKNOWN => "UNKNOWN",
        };

        // 格式化输出请求行
        write!(
            f,
            "method: {}, uri: {}, http_version: {}\n",
            method_str, self.uri, version_str
        )?;

        // 格式化输出请求参数信息
        for (key, value) in &self.params {
            write!(f, "params key: {}, value: {}\n", key, value)?;
        }

        // 格式化输出头部信息
        for (key, value) in &self.headers {
            write!(f, "headers key: {}, value: {}\n", key, value)?;
        }

        // 输出空行分隔头部和请求体
        write!(f, "\n")?;

        // 格式化输出请求体
        write!(f, "{}", self.body)
    }
}

impl HttpRequest {
    pub fn new(
        method: HttpMethod,
        uri: String,
        http_version: HttpVersion,
        params: HashMap<String, String>,
        headers: HashMap<String, String>,
        body: String,
    ) -> Self {
        HttpRequest {
            method,
            uri,
            http_version,
            params,
            headers,
            body,
        }
    }

    fn empty() -> Self {
        Self::new(
            HttpMethod::UNKNOWN,
            String::new(),
            HttpVersion::UNKNOWN,
            HashMap::new(),
            HashMap::new(),
            String::new(),
        )
    }

    pub fn parse_request(request_buf: &[u8]) -> HttpRequest {
        if let Ok(request_str) = std::str::from_utf8(&request_buf) {
            let lines: Vec<&str> = request_str.split('\n').collect();

            let mut method = HttpMethod::UNKNOWN;
            let mut uri = String::new();
            let mut http_version = HttpVersion::UNKNOWN;
            let mut params = HashMap::new();
            let mut headers = HashMap::new();
            let mut request_body = String::new();

            if let Some(request_line) = lines.first() {
                let parts: Vec<&str> = request_line.split_whitespace().collect();
                if parts.len() == 3 {
                    method = match parts[0] {
                        "GET" => HttpMethod::GET,
                        "POST" => HttpMethod::POST,
                        "DELETE" => HttpMethod::DELETE,
                        "OPTIONS" => HttpMethod::OPTIONS,
                        "HEAD" => HttpMethod::HEAD,
                        "CONNECT" => HttpMethod::CONNECT,
                        "PATCH" => HttpMethod::PATCH,
                        _ => HttpMethod::UNKNOWN,
                    };

                    let path_parts: Vec<&str> = parts[1].splitn(2, '?').collect();
                    uri = path_parts[0].to_string();

                    if path_parts.len() > 1 {
                        let param_str = path_parts[1];
                        for pair in param_str.split('&') {
                            if let Some((key, value)) = pair.split_once('=') {
                                params.insert(key.to_string(), value.to_string());
                            }
                        }
                    }

                    http_version = if parts[2] == "HTTP/1.1" {
                        HttpVersion::HTTP11
                    } else {
                        HttpVersion::UNKNOWN
                    };
                }
            }

            let mut in_body = false;
            for line in lines.into_iter().skip(1) {
                if line.trim().is_empty() {
                    in_body = true;
                    continue;
                }

                if in_body {
                    request_body.push_str(line);
                    request_body.push('\n');
                } else {
                    if let Some((key, value)) = line.split_once(':') {
                        headers.insert(key.trim().to_string(), value.trim().to_string());
                    }
                }
            }

            HttpRequest::new(method, uri, http_version, params, headers, request_body)
        } else {
            eprintln!("Received data is not valid UTF-8");
            HttpRequest::empty()
        }
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use tracing::info;
    // 注意这个惯用法：在 tests 模块中，从外部作用域导入所有名字。
    use super::*;

    #[test]
    fn test_str() {
        let non_empty_str: &str = ""; // 包含两个空格
        if non_empty_str.is_empty() {
            println!("字符串为空");
        } else {
            println!("字符串不为空");
        }
    }
}